package me.sdevil507.clouddisk.helper;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * 云盘帮助类
 *
 * @author sdevil507
 * created on 2021/3/19
 */
@SuppressWarnings("ALL")
@Slf4j
@Component
public class CloudDiskHelper {

    @Autowired
    private CloudDiskProperties cloudDiskProperties;

    /**
     * 获取阿里云OSS客户端对象
     *
     * @return ossClient
     */
    public OSSClient getOSSClient() {
        return new OSSClient(cloudDiskProperties.getEndpoint(), cloudDiskProperties.getAccessKey(), cloudDiskProperties.getSecertKey());
    }

    /**
     * 获取阿里云OSS客户端对象-内网
     *
     * @return ossClient
     */
    public OSSClient getInternalOSSClient() {
        return new OSSClient(cloudDiskProperties.getInternalEndpoint(), cloudDiskProperties.getAccessKey(), cloudDiskProperties.getSecertKey());
    }

    /**
     * 获取文件Object
     *
     * @param objectName为空 获取某个文件
     * @return
     */
    public OSSObject getObject(String objectName) {
        return getOSSClient().getObject(cloudDiskProperties.getBucket(), objectName);
    }

    /**
     * 生成OSS文件上传的需要的token生成
     *
     * @return STSToken
     */
    public Map<String,Object> getStsToken() {
        String roleSessionName = "ttcloud";
        try {
        String policy = "{" +
                "    \"Version\": \"1\", " +
                "    \"Statement\": [" +
                "        {" +
                "            \"Action\": [" +
                "                \"oss:PutObject\"," +
                "                \"oss:GetObject\"" +
                "            ], " +
                "            \"Resource\": [" +
                "                \"acs:oss:*:*:cloud-disk-dev\", " +
                "                \"acs:oss:*:*:cloud-disk-dev/*\" " +
                "            ], " +
                "            \"Effect\": \"Allow\"" +
                "        }" +
                "    ]" +
                "}";

            // 添加endpoint（直接使用STS endpoint，前两个参数留空，无需添加region ID）
            DefaultProfile.addEndpoint("", "", "Sts", cloudDiskProperties.getStsEndpoint());
            // 构造default profile（参数留空，无需添加region ID）
            IClientProfile profile = DefaultProfile.getProfile("", cloudDiskProperties.getStsAccessKeyId(), cloudDiskProperties.getStsAccessKeySecret());
            // 用profile构造client
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setMethod(MethodType.POST);
            request.setRoleArn(cloudDiskProperties.getStsRoleArn());
            request.setRoleSessionName(roleSessionName);
            // 若policy为空，则用户将获得该角色下所有权限
            request.setPolicy(policy);
            // 设置凭证有效时间
            request.setDurationSeconds(3600L);
            final AssumeRoleResponse response = client.getAcsResponse(request);
            Map<String,Object> resultMap = new HashMap<>();
            resultMap.put("securityToken",response.getCredentials().getSecurityToken());
            resultMap.put("accessKeySecret",response.getCredentials().getAccessKeySecret());
            resultMap.put("accessKeyId",response.getCredentials().getAccessKeyId());
            resultMap.put("bucket",cloudDiskProperties.getBucket());
            // 返回的是世界标准时间UTC格式，需要将UTC时间格式转换为CST格式
            resultMap.put("expiration",UTCtoCST(response.getCredentials().getExpiration()));
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * UTC时间转化CST
     * @param utc
     * @return
     */
    public static String UTCtoCST(String utc){
        ZonedDateTime zdt  = ZonedDateTime.parse(utc);
        LocalDateTime localDateTime = zdt.toLocalDateTime();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return formatter.format(localDateTime.plusHours(8));
    }

    /**
     * 上传图片至OSS
     *
     * @param file 上传文件
     * @return String 图片url地址
     */
    public String uploadObject2OSS(File file, String fileName) {
        OSS ossClient = new OSSClientBuilder().build(cloudDiskProperties.getInternalEndpoint(), cloudDiskProperties.getAccessKey(), cloudDiskProperties.getSecertKey());
        String fileUrl = null;
        InputStream is;
        try {
            // 以输入流的形式上传文件
            is = new FileInputStream(file);
            // 文件大小
            long fileSize = file.length();
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            // 上传的文件的长度
            metadata.setContentLength(is.available());
            // 指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            // 指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            // 指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            // 如果没有扩展名则填默认值application/octet-stream
            metadata.setContentType(getContentType(fileName));
            // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
            // 上传文件 (上传文件流的形式)
            ossClient.putObject(cloudDiskProperties.getBucket(), fileName, is, metadata);

            fileUrl = "https://" + cloudDiskProperties.getBucket() + "." + cloudDiskProperties.getEndpoint() + "/" + fileName;
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
        } finally {

            // 关闭OSSClient。
            ossClient.shutdown();
        }
        return fileUrl;
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public String getContentType(String fileName) {
        // 文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }
        if (".gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }
        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }
        if (".png".equalsIgnoreCase(fileExtension)) {
            return "image/png";
        }
        if (".html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }
        if (".txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }
        if (".vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }
        if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }
        if (".zip".equalsIgnoreCase(fileExtension)) {
            return "application/x-zip-compressed";
        }
        if (".xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }
        // 默认返回类型
        return "";
    }

    /**
     * 数据对应id
     *
     * @param id id
     */
    public OSSObject download(String fileName) throws IOException {
        OSS ossClient = new OSSClientBuilder().build(cloudDiskProperties.getEndpoint(), cloudDiskProperties.getAccessKey(), cloudDiskProperties.getSecertKey());
        OSSObject ossObject = ossClient.getObject(cloudDiskProperties.getBucket(), fileName);
        return ossObject;
    }
}
